package com.lanchetech.user.service.impl;

import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.lanchetech.bean.request.MeetingPageReq;
import com.lanchetech.bean.request.MeetingUserPageReq;
import com.lanchetech.bean.response.BasePageResp;
import com.lanchetech.bean.response.BaseResp;
import com.lanchetech.bean.response.ResultData;
import com.lanchetech.bean.util.PageHelpUtil;
import com.lanchetech.bean.vo.MeetingUserVO;
import com.lanchetech.bean.vo.MeetingVO;
import com.lanchetech.common.enums.*;
import com.lanchetech.dao.*;
import com.lanchetech.entity.*;
import com.lanchetech.service.DaoService;
import com.lanchetech.user.service.MeetingService;
import org.hashids.Hashids;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.util.*;
import java.util.stream.Collectors;

@Service
public class MeetingServiceImpl implements MeetingService {

    @Autowired
    MeetingMapper meetingMapper;

    @Autowired
    MeetingUserMapper meetingUserMapper;

    @Autowired
    IdentityMapper identityMapper;

    @Autowired
    AreaMapper areaMapper;

    @Autowired
    DaoService daoService;

    @Autowired
    UserRelationshipMapper userRelationshipMapper;

    @Autowired
    UserMapper userMapper;

    @Override
    public BaseResp editMeeting(Meeting req) {
        User user = (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        Identity identity = identityMapper.findOneByUserId(user.getId());
        if (!IdentityTypeEnum.SHAREHOLDER.getType().equals(identity.getType()) && TeacherLevelEnum.DEFAULT.getLevel().equals(identity.getTeacherLevel())) {
            return new BaseResp(ResultCode.NOT_TEACHER_OR_SHAREHOLDER);
        }
        if (req.getId() == null) {
            if (req.getStartTime().after(req.getEndTime())) {
                return new BaseResp(ResultCode.START_END_ERROR);
            }
            Area area = areaMapper.selectByPrimaryKey(req.getArea());
            req.setMergerName(area.getMergerName());
            req.setUserId(user.getId());
            req.setCurrentCount(0L);
            req.setStatus(ToggleEnum.ON.getStatus());
            req.setDeleted(DeletedEnum.DEFAULT.getStatus());
            req.setCreatedAt(new Date());
            req.setUpdatedAt(new Date());

            meetingMapper.insert(req);
        } else {
            Meeting meeting = meetingMapper.selectByPrimaryKey(req.getId());
            if (meeting.getUserId().equals(user.getId())) {
                req.setStatus(ToggleEnum.ON.getStatus());
                meetingMapper.updateByPrimaryKeySelective(req);
            }
        }
        return new BaseResp();
    }

    @Override
    public ResultData<MeetingVO> getMeetingDetail(Long id) {
        MeetingVO vo = new MeetingVO();
        Meeting meeting = meetingMapper.selectByPrimaryKey(id);
        BeanUtils.copyProperties(meeting, vo);
        User user = userMapper.selectByPrimaryKey(meeting.getUserId());
        vo.setUserNickname(user.getNickname());
        vo.setUserAvatar(user.getAvatar());
        return new ResultData<>(vo);
    }

    @Override
    public BaseResp deleteMeeting(Long id) {
        User user = (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        Meeting meeting = meetingMapper.selectByPrimaryKey(id);
        if (user.getId().equals(meeting.getUserId())) {
            meetingMapper.updateDeletedById(DeletedEnum.DELETED.getStatus(), id);
        }
        return new BaseResp();
    }

    @Override
    public ResultData<BasePageResp<MeetingVO>> getMyMeetingPage(MeetingPageReq req) {
        User user = (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        req.setUserId(user.getId());
        Page page = PageHelper.startPage(req.getPageNo(), req.getPageSize());
        List<MeetingVO> list = meetingMapper.findAllPage(req);
        return PageHelpUtil.buildPage(list, page);
    }

    @Override
    public ResultData<BasePageResp<MeetingVO>> getMeetingPage(MeetingPageReq req, User user) {
        req.setEndTime(new Date());
        req.setStatus(ToggleEnum.ON.getStatus());
        Page page = PageHelper.startPage(req.getPageNo(), req.getPageSize());
        List<MeetingVO> list = meetingMapper.findAllPage(req);
        if (!CollectionUtils.isEmpty(list)) {
            List<MeetingUser> meetingUsers = meetingUserMapper.findAllByUserIdAndStatus(user.getId(), ToggleEnum.ON.getStatus());
            List<Long> meetingIds = meetingUsers.stream().map(MeetingUser::getMeetingId).collect(Collectors.toList());

            Map<Long, User> userMap = daoService.getUserMap(list.stream().map(MeetingVO::getUserId).collect(Collectors.toList()));
            list.stream().forEach(item -> {
                item.setUserNickname(userMap.get(item.getUserId()).getNickname());
                item.setUserAvatar(userMap.get(item.getUserId()).getAvatar());
                item.setIsSignUp(meetingIds.contains(item.getId()));
            });
        }
        return PageHelpUtil.buildPage(list, page);
    }

    @Override
    public ResultData<BasePageResp<MeetingUserVO>> getMeetingUserPage(MeetingUserPageReq req) {
        User user = (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        List<MeetingUserVO> list = new ArrayList<>();
        Page page = new Page();
        if (req.getMeetingId() != null) {
            Meeting meeting = meetingMapper.selectByPrimaryKey(req.getMeetingId());
            if (meeting.getUserId().equals(user.getId())) {
                page = PageHelper.startPage(req.getPageNo(), req.getPageSize());
                list = meetingUserMapper.findAllPage(req);
                if (!CollectionUtils.isEmpty(list)) {
                    Map<Long, User> userMap = daoService.getUserMap(list.stream().map(MeetingUserVO::getUserId).collect(Collectors.toList()));
                    list.stream().forEach(item -> {
                        item.setUserNickname(userMap.get(item.getUserId()).getNickname());
                        item.setUserAvatar(userMap.get(item.getUserId()).getAvatar());
                    });
                }
            }
        }
        return PageHelpUtil.buildPage(list, page);
    }

    @Override
    public ResultData<BasePageResp<MeetingUserVO>> getMyMeetingUserPage(MeetingUserPageReq req) {
        User user = (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        Hashids hashids = new Hashids("meetUserId", 32);
        String hash = hashids.encode(user.getId());
        req.setUserId(user.getId());
        Page page = PageHelper.startPage(req.getPageNo(), req.getPageSize());
        List<MeetingUserVO> list = meetingUserMapper.findAllPage(req);
        if (!CollectionUtils.isEmpty(list)) {
            List<Meeting> meetingList = meetingMapper.findAllByIds(list.stream().map(MeetingUserVO::getMeetingId).collect(Collectors.toList()));
            Map<Long, Meeting> meetingMap = new HashMap<>();
            meetingList.stream().forEach(item -> {
                meetingMap.put(item.getId(), item);
            });
            list.stream().forEach(item -> {
                item.setHashId(hash);
                item.setMeeting(meetingMap.get(item.getMeetingId()));
            });
        }
        return PageHelpUtil.buildPage(list, page);

    }

    @Override
    public ResultData<Long> getJoinMeetCount(User user) {
        Long count = meetingUserMapper.countByUserIdAndVerifyStatus(user.getId(), ToggleEnum.ON.getStatus());
        return new ResultData<>(count == null ? 0 : count);
    }

    @Override
    public BaseResp joinMeeting(Long meetingId) {
        User user = (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        Meeting meeting = meetingMapper.selectByPrimaryKey(meetingId);
        Identity identity = identityMapper.findOneByUserId(meeting.getUserId());
        MeetingUser meetingUser = meetingUserMapper.findOneByUserIdAndMeetingId(user.getId(), meetingId);
        if (meetingUser != null && ToggleEnum.ON.getStatus().equals(meetingUser.getStatus())) {
            return new BaseResp(ResultCode.MEETING_USER_EXIST);
        }
        if (meeting.getLimitCount().compareTo(meeting.getCurrentCount()) <= 0) {
            return new BaseResp(ResultCode.MEETING_LIMIT);
        }
        if (DeletedEnum.DELETED.getStatus().equals(meeting.getDeleted()) || ToggleEnum.OFF.getStatus().equals(meeting.getStatus())) {
            return new BaseResp(ResultCode.MEETING_CLOSE);
        }
        if (meeting.getEndTime().before(new Date())) {
            return new BaseResp(ResultCode.MEETING_END);
        }
        UserRelationship userRelationship = userRelationshipMapper.findOneBySubordinateId(user.getId());
        if (userRelationship == null) {
            userRelationshipMapper.insert(UserRelationship.builder()
                    .superiorId(meeting.getUserId())
                    .subordinateId(user.getId())
                    .createdAt(new Date())
                    .status(RelationshipStatusEnum.NOT_BIND.getStatus())
                    .type(identity.getType())
                    .subordinateLevel(user.getLevel())
                    .updatedAt(new Date())
                    .build());
        }

        meetingMapper.updateCurrentCountById(meeting.getCurrentCount() + 1, meetingId);

        if (meetingUser == null) {
            meetingUserMapper.insert(MeetingUser.builder()
                    .userId(user.getId())
                    .meetingId(meetingId)
                    .status(ToggleEnum.ON.getStatus())
                    .verifyStatus(ToggleEnum.OFF.getStatus())
                    .createdAt(new Date())
                    .updatedAt(new Date())
                    .nickname(user.getNickname())
                    .build());
        } else {
            meetingUserMapper.updateStatusById(ToggleEnum.ON.getStatus(), meetingUser.getId());
        }

        return new BaseResp();
    }

    @Override
    public BaseResp cancelMeeting(Long meetingId) {
        User user = (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        Meeting meeting = meetingMapper.selectByPrimaryKey(meetingId);
        MeetingUser meetingUser = meetingUserMapper.findOneByUserIdAndMeetingId(user.getId(), meetingId);
        if (meeting != null && ToggleEnum.ON.getStatus().equals(meetingUser.getStatus())) {
            meetingUserMapper.updateStatusById(ToggleEnum.OFF.getStatus(), meetingUser.getId());
            meetingMapper.updateCurrentCountById(meeting.getCurrentCount() - 1, meetingId);
        }
        return new BaseResp();
    }

    @Override
    public BaseResp verifyConfirmMeetUser(String hashId, Long meetingId) {
        User user = (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        Meeting meeting = meetingMapper.selectByPrimaryKey(meetingId);
        if (!user.getUsername().equals(meeting.getVerifyUserPhone())) {
            return new BaseResp(ResultCode.VERIFY_FAIL);
        }
        Hashids hashids = new Hashids("meetUserId", 32);
        Long id = hashids.decode(hashId)[0];
        MeetingUser meetingUser = meetingUserMapper.findOneByUserIdAndStatusAndMeetingId(id, ToggleEnum.ON.getStatus(), meetingId);
        if (meetingUser == null) {
            return new BaseResp(ResultCode.MEETING_USER_NOT_EXIST);
        }
        if (VerifyStatusEnum.NOT_VERIFY.getStatus().equals(meetingUser.getVerifyStatus())) {
            meetingUser.setVerifyStatus(ToggleEnum.ON.getStatus());
            meetingUser.setVerifyTime(new Date());
            meetingUser.setUpdatedAt(new Date());
            meetingUserMapper.updateByPrimaryKeySelective(meetingUser);
        }
        return new BaseResp();
    }

    @Override
    public ResultData<MeetingUserVO> getMeetUserDetail(Long id) {
        MeetingUser meetingUser = meetingUserMapper.selectByPrimaryKey(id);
        MeetingUserVO vo = new MeetingUserVO();
        if (meetingUser != null) {
            Hashids hashids = new Hashids("meetUserId", 32);
            String hash = hashids.encode(meetingUser.getUserId());
            vo.setHashId(hash);
            BeanUtils.copyProperties(meetingUser, vo);
            vo.setMeeting(meetingMapper.selectByPrimaryKey(meetingUser.getMeetingId()));
            User user = userMapper.selectByPrimaryKey(meetingUser.getUserId());
            vo.setUserNickname(user.getNickname());
            vo.setUserAvatar(user.getAvatar());
        }
        return new ResultData<>(vo);
    }
}
